class CollisionManager 
{
  static CollisionManager _instance = null;
  List<List<CollisionQuadrant>> _quadrants;
  int stageWidth = 800, stageHeight = 400;
  int nRows = 8, nCols = 4;
  
  factory CollisionManager() 
  {
    if (_instance == null) {
      _instance = new CollisionManager._getInstance();
    }
    return _instance;
  }
  
  CollisionManager._getInstance()
  {
    _quadrants = new List<List<CollisionQuadrant>>(nRows);
    
    int qWidth = (stageWidth/nCols).toInt();
    int qHeight = (stageHeight/nRows).toInt();
    
    for(int i = 0 ; i < nRows; i++)
    {
      _quadrants[i] = new List<CollisionQuadrant>(nCols);
      
      for(int j = 0; j < nCols; j++)
      {
        _quadrants[i][j] = new CollisionQuadrant(j*qWidth,i*qHeight,qWidth,qHeight);
      }
    }
  }

  void removeObject(ICollidable o)
  {
    for(int i = 0; i < nRows; i++)
    {
      for(int j = 0; j <  nCols; j++)
      {
        _quadrants[i][j].removeObject(o);
      }
    }
  }
  
  void addObject(ICollidable o)
  {
    num qWidth = stageWidth/nCols;
    num qHeight = stageHeight/nRows;
    
    int firstCol = (o.topLeft.x/qWidth).toInt();
    int firstRow = (o.topLeft.y/qHeight).toInt();
    
    int lastCol = (o.botRight.x/qWidth).toInt();
    int lastRow = (o.botRight.y/qHeight).toInt();
    
    for(int i = firstRow; i <= lastRow; i++)
    {
      for(int j = firstCol; j <= lastCol; j++)
      {
        if(i >= 0 && i < nRows && j >=0 && j < nCols)
        {
          _quadrants[i][j].addObject(o);          
        }
      }
    }
  }
  
  
  void checkCollisions()
  {
    for(int i = 0 ; i < nRows; i++)
    {
      for(int j = 0; j < nCols; j++)
      {
        _quadrants[i][j].checkCollisions();
      }
    }
  }
  
  void objectPositionChanged(ICollidable o)
  {
    o.getQuadrants().forEach((CollisionQuadrant quadrant)
    {
      quadrant.onObjectMoved(o);
    });
    
    addObject(o);
  }
}
